function BytesToBits(len, num) {
	var o = "";
	while (len --) {
		if (num & 0x01) {
			o = "1" + o;
		} else {
			o = "0" + o;
		}
		num >>= 1;
	}
	return o;
}

function BitsToBytes(i) {
	o = 42;
	if (i.charAt(0) == '1') {
		o += 32;
	}
	if (i.charAt(1) == '1') {
		o += 16;
	}
	if (i.charAt(2) == '1') {
		o += 8;
	}
	if (i.charAt(3) == '1') {
		o += 4;
	}
	if (i.charAt(4) == '1') {
		o += 2;
	}
	if (i.charAt(5) == '1') {
		o += 1;
	}
	if (o >= 92) {
		o ++;
	}
	return String.fromCharCode(o);
}

function CompressConfirm() {
	if (confirm("Are you sure that you want to do this?  It can take a long time!")) {
		CompressCode();
	}
}

function CompressCode() {
	var letter_codes = new Array();
	var code_len = 1;
	var code_next = 0;
	var code_len_trigger = 1;
	var t_out = new StringMaker();
	var t_bits = "";
	var t_in = document.daForm.Orig.value;
	var prog = document.daForm.Progress;
	var last_code;
	var search_value;
	var mincode = 256, maxcode = -1;

	for (var i = 0; i < t_in.length; i ++) {
		var c = t_in.charCodeAt(i);
		if (mincode > c) {
			mincode = c;
		}
		if (maxcode < c) {
			maxcode = c;
		}
	}

	for (var i = mincode; i <= maxcode; i ++) {
		if (code_next == code_len_trigger) {
			code_len ++;
			code_len_trigger *= 2;
		}
		letter_codes[String.fromCharCode(i)] = code_next ++;
	}

	last_code = "";
	search_value = "";

	for (var i = 0; i < t_in.length; i ++) {
		search_value += t_in.charAt(i);
		if (i % 250 == 0) {
			prog.value = "Encoding:  " + i + " of " + t_in.length + " (" + Math.floor(100 * i / t_in.length) + "%)";
		}
		// TODO:  Possibly add "&& i != t_in.length - 1
		// That way the chunk after the for loop does not need to exist
		if (letter_codes[search_value] !== undefined	) {
			last_code = letter_codes[search_value];
		} else {
			if (code_next == code_len_trigger) {
				code_len ++;
				code_len_trigger <<= 1;
			}
			letter_codes[search_value] = code_next ++;
			t_bits += BytesToBits(code_len, last_code);
			while (t_bits.length >= 6) {
				t_out.append(BitsToBytes(t_bits));
				t_bits = t_bits.slice(6, t_bits.length);
			}
			search_value = t_in.charAt(i);
			last_code = letter_codes[search_value];
		}
	}
	if (code_next == code_len_trigger) {
		code_len ++;
		code_len_trigger <<= 1;
	}
	t_bits += BytesToBits(code_len, last_code);
	while (t_bits.length) {
		t_out.append(BitsToBytes(t_bits));
		t_bits = t_bits.slice(6, t_bits.length);
	}

	document.daForm.Comp.value = WrapInJS(t_out.toString(), mincode, maxcode);
	prog.value = "Done = " + t_in.length + " to " + document.daForm.Comp.value.length +
		" = " + (t_in.length - document.daForm.Comp.value.length) + " bytes of savings"
}

function CreatePopup(str) {
    ShowMeWindow = window.open("", "", "location=no,directories=no,menubar=no," +
        "resizable=yes,scrollbars=yes,status=yes,toolbar=no,width=300,height=240");
    ShowMeWindow.document.write(str);
    ShowMeWindow.document.close();
}

function WrapInJS(str, mincode, maxcode) {
	var out = '<sc' + 'ript language="JavaScript">' + "\n";
	out += 'd="'
	while (str.length > 80)
	{
		out += str.slice(0, 80) + "\"\n+\"";
		str = str.slice(80, str.length);
	}
	out += str + "\";\n";

	out += "var l,x,b,o,t,c,s,r,p,e;l=c=p=-1;x=b=e=0;o='';t=new Array();s=r=1;\n";
	out += "function g(){if(!b){if(x>=d.length)return-1;l=d.charCodeAt(x);\n";
	out += "if(l>92)l--;l-=42;x++;b=6;}return(l>>--b)&1;}\n";
	out += "function a(){var b,n=0,c=0;for(;n<s;n++)c=c*2+(b=g());return (b<0)?-1:c;}\n";
	out += "for (var i=" + mincode + ";i<=" + maxcode + ";i++){if(e+1==r){s++;r*=2;}t[e++]=String.fromCharCode(i);}\n";
	out += "while((c=a())>=0){if(p>=0)t[e++]=t[p]+t[c].charAt(0);o+=t[c];p=c;\n";
	out += "if(t.length+1==r){r*=2;s++;}}\n";
	out += "document.write(o);\n";
	out += "</sc" + "ript>\n";

	return out;
}